import re

import numpy as np
import pandas as pd
# from wgdi import base

class Solution:
    # 定义变量
    def __init__(self):
        self.gap_penality = -1
        self.over_length = 100000
        self.mg1 = 4
        self.mg2 = 4
        self.over_gap = 5
        self.path_dict ={}
        self.rows = []
        self.cols = []
        self.evalue = 0
        self.score = 0
        self.matold=[]
    # 获取矩阵

    def get_martix(self):
        mat = pd.read_csv('mat1.csv', index_col=0)
        # mat = mat.replace(1.50)
        mat = mat.loc[:, mat.sum(axis=0) != 0]
        self.mat = mat.loc[mat.sum(axis=1) != 0, :]
        self.mat.columns = self.mat.columns.astype(int)
        self.mat.index = self.mat.index.astype(int)
        self.matold = self.mat.copy()
        # print(mat)
        (self.rows, self.cols) = mat.shape
        # print(mat.shape)
        self.mat=self.mat.astype(np.int16)
        # print(self.score1)
        # path1 斜向下，path2 斜向上
        self.score1 = self.mat.copy()
        self.score2 = self.mat.copy()
        self.mat_new = self.mat.copy()
        self.path1 = pd.DataFrame([['' for i in range(self.cols)] for j in range(
            self.rows)], index=mat.index, columns=self.mat.columns)
        self.path2 = pd.DataFrame([['' for i in range(self.cols)] for j in range(
            self.rows)], index=mat.index, columns=self.mat.columns)
        self.path_lenth1 = pd.DataFrame([['' for i in range(self.cols)] for j in range(
            self.rows)], index=mat.index, columns=self.mat.columns)
        self.path2 = pd.DataFrame([['' for i in range(self.cols)] for j in range(
            self.rows)], index=mat.index, columns=self.mat.columns)

    def run(self):
        self.get_martix()
        loc, evalues, scores = [], [], []
        # self.maxPath()
        while(self.over_length >= 2):
            print(self.over_length,self.evalue,self.score)
            if self.maxPath():
                loc.append(self.path)
                evalues.append(self.evalue)
                scores.append(self.score)
        # break
        # print('out:', loc)
        # print('out:', evalues)
        return loc, evalues, scores

    def maxPath(self):
        # print(self.mat_new)
        # print(self.score2)
        # print(self.path1.loc[:,[1,2,3,4,5]])
        # 影响的范围，点坐标 row，col 的 mg1,mg2 范围，还需要考虑边界
        print(self.mat_new.shape)
        

        mat_new_index, mat_new_columns =  self.mat_new.index, self.mat_new.columns
        # print(mat_new_index[1]-mat_new_index[0])
        # path1 处理
        for i, row in enumerate(mat_new_index):
            for j, col in enumerate(mat_new_columns):
                if self.mat_new.loc[row, col]:
                    continue
                for row_i in mat_new_index[i+1:i+1+self.mg1]:
                    if row_i - row > self.mg1:
                        break
                    for col_j in mat_new_columns[j+1:j+1+self.mg2]:
                        if col_j - col > self.mg2:
                            break
                        if self.mat_new.loc[row_i, col_j] :
                            continue
                        s = self.score1.loc[row, col]+self.mat_new.loc[row_i,
                                                                       col_j]+(row_i-row-1+col_j-col-1)*self.gap_penality
                        if self.score1.loc[row_i, col_j] < s:
                            self.score1.loc[row_i, col_j] = s

                            self.path1.loc[row_i,
                                           col_j] = self.path1.loc[row, col]
                            self.path1.loc[row_i,
                                           col_j] += str(row)+':'+str(col)+'_'
        # path2 处理
        mat_new_index = mat_new_index[::-1]
        print(mat_new_index)
        for i, row in enumerate(mat_new_index):
            for j, col in enumerate(mat_new_columns):
                if self.mat_new.loc[row, col] ==0:
                    continue
                print(row,col,i,j)
                for row_i in mat_new_index[i+1:i+1+self.mg1]:
                    if row - row_i > self.mg1 or row_i >= row:
                        break
                    # print(row_i)
                    for col_j in mat_new_columns[j+1:j+1+self.mg2]:
                        if col_j - col > self.mg2:
                            break
                        if self.mat_new.loc[row_i, col_j]==0:
                            continue
                        print('---',row_i,col_j)
                        s = self.score2.loc[row, col]+self.mat_new.loc[row_i,
                                                                       col_j]+(row-row_i-1+col_j-col-1)*self.gap_penality
                        if self.score2.loc[row_i, col_j] < s:
                            self.score2.loc[row_i, col_j] = s
                            # print('++++',row, col,row_i, col_j,s)
                            self.path2.loc[row_i,
                                           col_j] = self.path2.loc[row, col]
                            self.path2.loc[row_i,
                                           col_j] += str(row)+':'+str(col)+'_'
        # print(self.score1)
        # print(self.score2)
        # print(self.path2)
        if self.score1.empty or self.score2.empty or self.score1.stack().max() == self.score2.stack().max() == 0:
            self.over_length = 0
            self.path = []
            self.evalue = np.nan
            self.score = 0
            return False
        #按照打分来选取共线性
        if self.score1.stack().max() >= self.score2.stack().max():
            (x, y) = self.score1.stack().idxmax()
            self.score = self.score1.loc[x, y]
            self.path1.loc[x, y] += str(int(x))+':'+str(y)+'_'
            # print(self.path1.loc[x, y])
            array = re.findall('\d+', self.path1.loc[x, y])
            self.path = [[int(array[i]), int(array[i+1])]
                         for i in range(0, len(array), 2)]
            # print(self.score1)
            # print(self.path1.loc[x, y])
            
        else:
            (x, y) = self.score2.stack().idxmax()
            self.score = self.score2.loc[x, y]
            self.path2.loc[x, y] += str(int(x))+':'+str(y)+'_'
            # print(self.path2.loc[x, y])
            array = re.findall('\d+', self.path2.loc[x, y])
            # print(array)
            self.path = [[int(array[i]), int(array[i+1])]
                         for i in range(0, len(array), 2)]
            # print(self.score2)
            # print(self.path2)
        # print(self.path)
        print(x,y,self.score)
        self.over_length = len(self.path)
        # self.evalue = 0
        (x1, y1), (x2, y2) = self.path[0], self.path[-1]
        x1, x2 = sorted([x1, x2])
        y1, y2 = sorted([y1, y2])
        x_gap, y_gap = [], []
        for k in self.mat.index:
            if k <= x2+self.mg1 and k >= x1 - self.mg1:
                x_gap.append(k)
        for k in self.mat.columns:
            if k <= y2 + self.mg2 and k >= y1-self.mg2:
                y_gap.append(k)
        del_x = [k for k in self.mat.index if x1 <= k <= x2]
        del_y = [k for k in self.mat.columns if y1 <= k <= y2]
        # print(del_x,del_y)
        # print(len(del_x),len(del_y))
        # del_x,del_y = self.del_area()
        #这里首先判定共线性是否合适，然后判定后续
        # print(len(self.path))
        # print(len(self.path), self.path, self.evalue, self.score)
        mark = False
        if  self.right_path():
            for row, col in self.path:
                self.mat.loc[row, col] = 0
            self.rows ,self.cols = del_x,del_y  #youwenti
            # print(len(self.path), self.path, self.evalue, self.score)
            #删除区域
        else:
            mark = True
            # print(self.path_dict)
            y_gap = [k for k in y_gap if k not in self.cols]
            #不删除点，重新计算打分，路径

        # del_x,del_y = self.del_area()
        # self.score1.loc[del_x, del_y] = 0
        # self.score2.loc[del_x, del_y] = 0
        # self.path1.loc[del_x, del_y] = [['' for i in range(len(del_y))] for j in range(
        #     len(del_x))]
        # self.path2.loc[del_x, del_y] = [['' for i in range(len(del_y))] for j in range(
        #     len(del_x))]
        
        # (del_x,del_y,x_gap,y_gap) = self.del_area()
        # self.rows ,self.cols = del_x,del_y
        # print(del_x,del_y)
        # self.score1.to_csv('out1.csv')
        # self.path1.to_csv('out2.csv')
        # print(self.score1)
        # print(min(x_gap),max(x_gap), min(y_gap),max(y_gap))
        # print(self.score1.loc[136,1198])
        # print(self.path1.loc[136,1198])
        self.score1.loc[x_gap, y_gap] = 0
        self.score2.loc[x_gap, y_gap] = 0
        self.path1.loc[x_gap, y_gap] = ''
        self.path2.loc[x_gap, y_gap] = ''
        self.mat_new = self.mat.loc[x_gap,y_gap]
        self.mat_new = self.mat_new.loc[:, self.mat_new.sum(axis=0) != 0]
        self.mat_new = self.mat_new.loc[self.mat_new.sum(axis=1) != 0, :]
        # print(self.path1,self.path2)
        self.evalue = self.evalue_estimated()
        # print(self.evalue)
        # print(str(mark)+'\n')
        # input()
        if  mark:
            return False
        
        return True

    # def del_area(self): #共线性区域
    #     (x1, y1), (x2, y2) = self.path[0], self.path[-1]
    #     x1, x2 = sorted([x1, x2])
    #     y1, y2 = sorted([y1, y2])
    #     del_x = [k for k in self.mat.index if x1 <= k <= x2+1]
    #     del_y = [k for k in self.mat.columns if y1 <= k <= y2+1]
    #     return del_x,del_y

    def right_path(self):
        for k in self.path:
            if str(k[0])+':'+str([1]) in self.path_dict:
                return False
        for k in self.path:
            self.path_dict[str(k[0])+':'+str(k[1])] = 1
        return True


    def evalue_estimated(self):
        (x1, y1), (x2, y2) = self.path[0], self.path[-1]
        x1, x2 = sorted([x1, x2])
        y1, y2 = sorted([y1, y2])
        del_x = [k for k in self.matold.index if x1 <= k <= x2]
        del_y = [k for k in self.matold.columns if y1 <= k <= y2]
        mat = self.matold.loc[del_x, del_y]
        mat = mat.loc[:, mat.sum(axis=0) != 0]
        mat = mat.loc[mat.sum(axis=1) != 0, :]
        mat[mat > 0] = 1
        m = len(self.path)
        # N = int(mat.stack().sum())+mat.sum().prod()
        L1, L2 = x2-x1+1, y2-y1+1
        # l1_cha = [abs(self.path[i][0]-self.path[i-1][0]) for i in range(1, m)]
        # l2_cha = [abs(self.path[i][1]-self.path[i-1][1])  for i in range(1, m)]
        # print(mat)
        a=m/L1*m/L2/mat.sum().prod()
        # print(a,mat.sum().prod(),'+++++')
        # print(l1_cha,l2_cha)
        # print(N,m)
        # if N>50:
        #     return 0
        # for i in range(m-1):
        #     a *= l1_cha[i]*l2_cha[i]/L1/L2
        # a *= np.math.factorial(N)/np.math.factorial(N-m)
        # print(N,m,a)
        return '{:g}'.format(a)

def rewriteblock(data, fout,gff1,gff2):
    loc, evalues, scores = data
    num = 0
    rewriteblock
    fout = open(fout, 'w')
    for i in  range(len(loc)):
        num += 1
        fout.write('the '+str(num)+'th path length ' +
                    str(len(loc[i]))+'\n')
        for k in loc[i]:
            name1 = gff1[gff1['order']==k[0]+1].index[0]
            name2 = gff2[gff2['order']==k[1]+1].index[0]
            k[0] = name1 +' '+str(k[0])
            k[1] = name2 +' '+str(k[1])
            s = ' '.join([str(i) for i in k])
            fout.write(s+'\n')
        fout.write('>LOCALE p-value :'+ str(evalues[i]) +'\n\n')

s = Solution()
data= s.run()
# data =[[[[15, 3], [14, 4], [13, 5], [11, 6], [7, 14], [6, 17], [3, 20]]],[0],[0]]
# lens1 = base.newlens('dotplot/vv.lens', 'order')
# lens2 = base.newlens('dotplot/pp.lens', 'order')
# # lens1 = lens1[lens1 > 4]
# # lens2 = lens2[lens2 > 4]
# gff1 = base.newgff('dotplot/vv160s.gff')
# gff2 = base.newgff('dotplot/pp72s.gff')
# gff1 = gff1[gff1['chr'].isin(lens1.index)]
# gff2 = gff2[gff2['chr'].isin(lens2.index)]
# # print(gff1.head())
# # print(gff1['order'].head())
# rewriteblock(data,'1.block.txt',gff1,gff2)
# print(result)
